package com.ym.core.es.engine;

import cn.hutool.core.bean.BeanUtil;
import com.ym.core.es.config.HighlightResultMapper;
import com.ym.core.es.domain.index.BaseIdIndex;
import com.ym.core.es.query.QueryParser;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.update.UpdateRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 抽象接口定义
 */
@Slf4j
@Component
public class SearchQueryEngine {

	@Autowired
	protected ElasticsearchTemplate elasticsearchTemplate;

	@Autowired
	private HighlightResultMapper highlightResultMapper;

	/**
	 * 删除索引
	 *
	 * @param indexClass
	 */
	public <T extends BaseIdIndex> void deleteIndex(Class<T> indexClass) {
		if (elasticsearchTemplate.indexExists(indexClass)) {
			elasticsearchTemplate.deleteIndex(indexClass);
		}
	}

	/**
	 * 根据文档ID删除
	 *
	 * @param indexClass
	 * @param docIds
	 */
	public <T extends BaseIdIndex> void deleteIndexByDocIds(Class<T> indexClass, String... docIds) {
		CriteriaQuery query = new CriteriaQuery(Criteria.where("id").in(docIds));
		elasticsearchTemplate.delete(query, indexClass);
	}

	/**
	 * 根据查询条件删除
	 *
	 * @param indexClass
	 * @param query
	 */
	public <T extends BaseIdIndex> void deleteIndexByQuery(Class<T> indexClass, CriteriaQuery query) {
		elasticsearchTemplate.delete(query, indexClass);
	}


	/**
	 * 创建索引
	 *
	 * @param indexName
	 * @param <T>
	 */
	public <T extends BaseIdIndex> void createIndex(Class<T> indexName, Map<String, String> setting) {
		if (!elasticsearchTemplate.indexExists(indexName)) {
			elasticsearchTemplate.createIndex(indexName, setting);
			elasticsearchTemplate.putMapping(indexName);
		}
	}

	/**
	 * 创建索引
	 *
	 * @param indexName
	 * @param <T>
	 */
	public <T extends BaseIdIndex> void createIndex(Class<T> indexName) {
		if (!elasticsearchTemplate.indexExists(indexName)) {
			elasticsearchTemplate.createIndex(indexName);
		}
	}

	/**
	 * 新增或者修改
	 *
	 * @param t
	 */
	public void saveOrUpdate(BaseIdIndex t) {
		UpdateQuery updateQuery = indexCovertUpdate(t);
		elasticsearchTemplate.update(updateQuery);
	}


	/**
	 * 新增或者修改
	 *
	 * @param list
	 * @param <T>
	 */
	public <T extends BaseIdIndex> void saveOrUpdate(List<T> list) {
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		List<UpdateQuery> updateList = list.stream().map(this::indexCovertUpdate).collect(Collectors.toList());
		elasticsearchTemplate.bulkUpdate(updateList);
	}

	/**
	 * 分页查询
	 *
	 * @param query
	 * @param clazz
	 * @return
	 */
	public <T extends BaseIdIndex> Page<T> queryForPage(QueryParser query, Class<T> clazz) {
		Page<T> pageData = elasticsearchTemplate.queryForPage(query.build(), clazz,highlightResultMapper);
		return pageData;
	}


	public <T extends BaseIdIndex> List<T> queryForList(QueryParser query, Class<T> clazz) {
		return this.queryForPage(query, clazz).getContent();
	}

	protected <T> Document getDocument(T t) {
		Document annotation = t.getClass().getAnnotation(Document.class);
		if (annotation == null) {
			throw new UnsupportedOperationException("Can't find annotation @Document on " + t.getClass().getName());
		}
		return annotation;
	}

	/**
	 * 索引对象转为es的update对象
	 *
	 * @param t
	 * @return
	 */
	public <T extends BaseIdIndex> UpdateQuery indexCovertUpdate(T t) {
		if (t == null) {
			throw new UnsupportedOperationException("对象不能为空!");
		}
		if (null == t.getId()) {
			throw new UnsupportedOperationException("业务ID不能为空!");
		}
		Document document = getDocument(t);
		UpdateQuery updateQuery = new UpdateQuery();
		updateQuery.setIndexName(document.indexName());
		updateQuery.setId(t.getId());
		// doc()的参数不能为json字符串或t对象，只能为map
		UpdateRequest updateRequest = new UpdateRequest();
		updateRequest.index(updateQuery.getIndexName());
		updateRequest.doc(BeanUtil.beanToMap(t));
		updateRequest.id(updateQuery.getId());
		updateQuery.setUpdateRequest(updateRequest);
		updateQuery.setDoUpsert(true);
		updateQuery.setClazz(t.getClass());
		return updateQuery;
	}

}
